Chapter 10: Tibbles

Read R4ds Chapter 10: Tibbles, sections 1-3.

10.1: Introduction

Load the tidyverse package.

library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.2.1 --
v ggplot2 3.1.0     v purrr   0.2.5
v tibble  1.4.2     v dplyr   0.7.8
v tidyr   0.8.2     v stringr 1.3.1
v readr   1.3.0     v forcats 0.3.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

10.2: Creating tibbles

Enter your code chunks for Section 10.2 here.

Describe what each chunk code does.

as_tibble(iris)

tibble is a like an improved form of a data.frame.

tibble(
  x = 1:5, 
  y = 1, 
  z = x ^ 2 + y)

tibble does not change the inputs or names of variables and never creates row names.

tb <- tibble(
  `:)` = "smile", 
  ` ` = "space",
  `2000` = "number"
)
tb

back ticks allow you to refer to the variables in non-syntactic names.

tribble(
  ~x, ~y, ~z,
  #--|--|----
  "a", 2, 3.6,
  "b", 1, 8.5
)

tribble means transposed tibble. It is “customized for data entry in code: column headings are defined by formulas (start with ~) and separated by commas, this makes it easy to read.”

10.3: Tibbles vs data.frame

Enter your code chunks for Section 10.3 here.

Describe what each chunk code does.

tibble(
  a = lubridate::now() + runif(1e3) * 86400,
  b = lubridate::today() + runif(1e3) * 30,
  c = 1:1e3,
  d = runif(1e3),
  e = sample(letters, 1e3, replace = TRUE))

This shows only the first ten rows and columns that fit on the screen. This allows large data to be easy to work with.

nycflights13::flights %>% 
  print(n = 10, width = Inf)

This allows you to print the data frame explicitly and control the number of rows and the width of the display. width = inf shows all the columns.

nycflights13::flights %>% 
  View()

the view() function allows you to view the whole data set in a table.

df <- tibble(
  x = runif(5),
  y = rnorm(5))
df$x
[1] 0.72324706 0.04123625 0.97885578 0.71327709
[5] 0.83193281
df[["x"]]
[1] 0.72324706 0.04123625 0.97885578 0.71327709
[5] 0.83193281
df[[1]]
[1] 0.72324706 0.04123625 0.97885578 0.71327709
[5] 0.83193281

These functions allow you to extract a single variable by name or position.

df %>% .$x
[1] 0.72324706 0.04123625 0.97885578 0.71327709
[5] 0.83193281
df %>% .[["x"]]
[1] 0.72324706 0.04123625 0.97885578 0.71327709
[5] 0.83193281

This also allows extraction of a single variable, but using pipe and the placeholder “.” is used.

10.4: Not required

Section 10.5 Questions

Answer the questions completely. Use code chunks, text, or both, as necessary.

mtcars
as_tibble(mtcars)
str(mtcars)
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
class(mtcars)
[1] "data.frame"

1: How can you tell if an object is a tibble? (Hint: try printing mtcars, which is a regular data frame). Identify at least two ways to tell if an object is a tibble. Hint: What does as_tibble() do? What does class() do? What does str() do? A tibble uses row numbers instead of names and displays 9 columns (whereas the data frame only shows six columns–without scrolling). str() lists the data structure of the data frame. Class() tells you what type of class the variable is; for example mtcars is a data.frame.

2: Compare and contrast the following operations on a data.frame and equivalent tibble. What is different? Why might the default data frame behaviours cause you frustration?

df <- data.frame(abc = 1, xyz = "a")
df$x
[1] a
Levels: a
df[, "xyz"]
[1] a
Levels: a
df[, c("abc", "xyz")]

The default data frame functions automatically choose a title for your rows/columns. In tibble, it does not make up names, it chooses it from the data given.

Chapter 11: Importing data

Read R4ds Chapter 11: Data Import, sections 1, 2, and 5.

11.1 Introduction

Nothing to do here unless you took a break and need to reload tidyverse.

11.2 Getting started.

Do not run the first code chunk of this section, which begins with heights <- read_csv("data/heights.csv"). You do not have that data file so the code will not run.

Enter and run the remaining chunks in this section.

read_csv("a,b,c
1,2,3
4,5,6")
read_csv("The first line of metadata
  The second line of metadata
  x,y,z
  1,2,3", skip = 2)
read_csv("# A comment I want to skip
  x,y,z
  1,2,3", comment = "#")
read_csv("1,2,3\n4,5,6", col_names = FALSE)
read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))
read_csv("a,b,c\n1,2,.", na = ".")

11.2 Questions

1: What function would you use to read a file where fields were separated with “|”? read_delim("file.csv", delim = "|") is the function you would use to read the file with entries separated with “|”.

2: (This question is modified from the text.) Finish the two lines of read_delim code so that the first one would read a comma-separated file and the second would read a tab-separated file. You only need to worry about the delimiter. Do not worry about other arguments. Replace the dots in each line with the rest of your code.

Comma-separated

file <- read_delim("file.csv", delim = ",")

Tab-separated

file <- read_delim("file.csv", delim = "\t")

3: What are the two most important arguments to read_fwf()? Why? col_position and col_types are the most important arguments to read_fwf because they allow you to name your columns and determine the type of data listed in the columns.

4: Skip this question

5: Identify what is wrong with each of the following inline CSV files. What happens when you run the code?

read_csv("a,b\n1,2,3\n4,5,6")
2 parsing failures.
row col  expected    actual         file
  1  -- 2 columns 3 columns literal data
  2  -- 2 columns 3 columns literal data
read_csv("a,b,c\n1,2\n1,2,3,4")
2 parsing failures.
row col  expected    actual         file
  1  -- 3 columns 2 columns literal data
  2  -- 3 columns 4 columns literal data
read_csv("a,b\n\"1")
2 parsing failures.
row col                     expected    actual         file
  1  a  closing quote at end of file           literal data
  1  -- 2 columns                    1 columns literal data
read_csv("a,b\n1,2\na,b")
read_csv("a;b\n1;3")

“parsing failures” is the error message associated with the first file. This is because it is set for 2 columns and some of the data has three columns. This causes some of the information to be left out of the table and not displayed. The next file is set for three columns, but only has 2 entries. The next file is set for 2 columns, but only has one entry. The next file has some of the data listed as headers and this is redundant. This is due to data being improperly recorded. The next file is listed with semicolons, but the function used reads entries separated with commas. This causes the data to be listed in the same column because tibble does not recognize the entries as separate entries.

11.3 and 11.4: Not required

11.5: Writing to a file

Just read this section. You may find it helpful in the future to save a data file to your hard drive. It is basically the same format as reading a file, except that you must specify the data object to save, in addition to the path and file name.

11.6 Not required

Chapter 18: Pipes

Read R4ds Chapter 18: Pipes, sections 1-3.

Nothing to do otherwise for this chapter. Is this easy or what?

Note: Trying using pipes for all of the remaining examples. That will help you understand them.

Chapter 12: Tidy Data

Read R4ds Chapter 12: Tidy Data, sections 1-3, 7.

12.1 Introduction

Nothing to do here unless you took a break and need to reload the tidyverse.

12.2 Tidy data

Study Figure 12.1 and relate the diagram to the three rules listed just above them. Relate that back to the example I gave you in the notes. Bear this in mind as you make data tidy in the second part of this assignment.

You do not have to run any of the examples in this section.

12.3

Read and run the examples through section 12.3.1 (gathering), including the example with left_join(). We’ll cover joins later.

table4a
table4a %>% 
  gather(`1999`, `2000`, key = "year", value = "cases")
table4b %>% 
  gather(`1999`, `2000`, key = "year", value = "population")
tidy4a <- table4a %>% 
  gather(`1999`, `2000`, key = "year", value = "cases")
tidy4b <- table4b %>% 
  gather(`1999`, `2000`, key = "year", value = "population")
left_join(tidy4a, tidy4b)
Joining, by = c("country", "year")
table2
table2 %>%
    spread(key = type, value = count)

12.3 Questions

2: Why does this code fail? Fix it so it works.

table4a %>% 
  gather(1999, 2000, key = "year", value = "cases")
#> Error in inds_combine(.vars, ind_list): Position must be between 0 and n
table4a %>% 
  gather(`1999`, `2000`, key = "year", value = "cases")

Tthere must be backticks surrounding the years.

That is all for Chapter 12. On to the last chapter.

Chapter 5: Data transformation

Read R4ds Chapter 5: Data Transformation, sections 1-4.

Time to get small.

5.1: Introduction

Load the necessary libraries. As usual, type the examples into and run the code chunks.

library(nycflights13)
package 㤼㸱nycflights13㤼㸲 was built under R version 3.5.2
library(tidyverse)
nycflights13::flights
flights
filter(flights, month == 1, day == 1)
jan1 <- filter(flights, month == 1, day == 1)
(dec25 <- filter(flights, month == 12, day == 25))
#> # A tibble: 719 x 19
filter(flights, month == 1)
sqrt(2) ^ 2 == 2
[1] FALSE
near(sqrt(2) ^ 2,  2)
[1] TRUE
near(1 / 49 * 49, 1)
[1] TRUE

5.2: Filter rows with filter()

Study Figure 5.1 carefully. Once you learn the &, |, and ! logic, you will find them to be very powerful tools.

filter(flights, month == 11 | month == 12)
nov_dec <- filter(flights, month %in% c(11, 12))
filter(flights, !(arr_delay > 120 | dep_delay > 120))
filter(flights, arr_delay <= 120, dep_delay <= 120)
NA > 5
[1] NA
10 == NA
[1] NA
NA + 10
[1] NA
NA / 2
[1] NA
NA == NA
[1] NA
x <- NA

y <- NA

x == y
[1] NA
is.na(x)
[1] TRUE
df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)

filter(df, is.na(x) | x > 1)

5.2 Questions

1.1: Find all flights with a delay of 2 hours or more.

filter(flights, (arr_delay > 120 | dep_delay > 120))

1.2: Flew to Houston (IAH or HOU)

filter(flights, dest == 'IAH' | dest == 'HOU')

1.3: Were operated by United (UA), American (AA), or Delta (DL).

filter(flights, carrier == 'UA' | carrier == 'AA' | carrier == 'DL')

1.4: Departed in summer (July, August, and September).

filter(flights, month >= 7 & month <= 9)

1.5: Arrived more than two hours late, but didn’t leave late.

filter(flights, arr_delay > 120, dep_delay <= 0)

1.6: Were delayed by at least an hour, but made up over 30 minutes in flight. This is a tricky one. Do your best.

filter(flights, dep_delay >= 60, dep_delay-arr_delay > 30)

1.7: Departed between midnight and 6am (inclusive)

filter(flights, dep_time <=600 | dep_time == 2400)

2: Another useful dplyr filtering helper is between(). What does it do? Can you use it to simplify the code needed to answer the previous challenges?

filter(flights, between(month, 7, 9))
filter(flights, !between(dep_time, 601, 2359))

It uses the data between the variables listed. It does simplify the last two questions!

3: How many flights have a missing dep_time? What other variables are missing? What might these rows represent?

summary(flights)
      year          month             day       
 Min.   :2013   Min.   : 1.000   Min.   : 1.00  
 1st Qu.:2013   1st Qu.: 4.000   1st Qu.: 8.00  
 Median :2013   Median : 7.000   Median :16.00  
 Mean   :2013   Mean   : 6.549   Mean   :15.71  
 3rd Qu.:2013   3rd Qu.:10.000   3rd Qu.:23.00  
 Max.   :2013   Max.   :12.000   Max.   :31.00  
                                                
    dep_time    sched_dep_time   dep_delay      
 Min.   :   1   Min.   : 106   Min.   : -43.00  
 1st Qu.: 907   1st Qu.: 906   1st Qu.:  -5.00  
 Median :1401   Median :1359   Median :  -2.00  
 Mean   :1349   Mean   :1344   Mean   :  12.64  
 3rd Qu.:1744   3rd Qu.:1729   3rd Qu.:  11.00  
 Max.   :2400   Max.   :2359   Max.   :1301.00  
 NA's   :8255                  NA's   :8255     
    arr_time    sched_arr_time   arr_delay       
 Min.   :   1   Min.   :   1   Min.   : -86.000  
 1st Qu.:1104   1st Qu.:1124   1st Qu.: -17.000  
 Median :1535   Median :1556   Median :  -5.000  
 Mean   :1502   Mean   :1536   Mean   :   6.895  
 3rd Qu.:1940   3rd Qu.:1945   3rd Qu.:  14.000  
 Max.   :2400   Max.   :2359   Max.   :1272.000  
 NA's   :8713                  NA's   :9430      
   carrier              flight       tailnum         
 Length:336776      Min.   :   1   Length:336776     
 Class :character   1st Qu.: 553   Class :character  
 Mode  :character   Median :1496   Mode  :character  
                    Mean   :1972                     
                    3rd Qu.:3465                     
                    Max.   :8500                     
                                                     
    origin              dest              air_time    
 Length:336776      Length:336776      Min.   : 20.0  
 Class :character   Class :character   1st Qu.: 82.0  
 Mode  :character   Mode  :character   Median :129.0  
                                       Mean   :150.7  
                                       3rd Qu.:192.0  
                                       Max.   :695.0  
                                       NA's   :9430   
    distance         hour           minute     
 Min.   :  17   Min.   : 1.00   Min.   : 0.00  
 1st Qu.: 502   1st Qu.: 9.00   1st Qu.: 8.00  
 Median : 872   Median :13.00   Median :29.00  
 Mean   :1040   Mean   :13.18   Mean   :26.23  
 3rd Qu.:1389   3rd Qu.:17.00   3rd Qu.:44.00  
 Max.   :4983   Max.   :23.00   Max.   :59.00  
                                               
   time_hour                  
 Min.   :2013-01-01 05:00:00  
 1st Qu.:2013-04-04 13:00:00  
 Median :2013-07-03 10:00:00  
 Mean   :2013-07-03 05:22:54  
 3rd Qu.:2013-10-01 07:00:00  
 Max.   :2013-12-31 23:00:00  
                              

8255 have missing dep_time and dep_delay. 8713 missing arr_time. 9430 missing arr_delay. 9430 missing air_time. These rows might represent empty rows or just forgotten data (human error).

4: Why is NA ^ 0 not missing? Why is NA | TRUE not missing? Why is FALSE & NA not missing? Can you figure out the general rule? (NA * 0 is a tricky counterexample!)

NA ^ 0
[1] 1
NA | TRUE
[1] TRUE
FALSE & NA
[1] FALSE

NA ^ 0 = 1. NA | TRUE means if either NA or true is true, then the whole set = TRUE. FALSE & NA is not missing; one of the terms = FALSE. If one term is correct, then the function counts the whole term as correct seems to be the general rule.

Note: For some context, see this thread

5.3 Arrange with arrange()

arrange(flights, year, month, day)
arrange(flights, desc(dep_delay))
df <- tibble(x = c(5, 2, NA))
arrange(df, x)
arrange(df, desc(x))

5.3 Questions

1: How could you use arrange() to sort all missing values to the start? (Hint: use is.na()). Note: This one should still have the earliest departure dates after the NAs. Hint: What does desc() do?

arrange(df, desc(is.na(x)))

2: Sort flights to find the most delayed flights. Find the flights that left earliest.

arrange(flights, desc(dep_delay))
arrange(flights, dep_delay)

This question is asking for the flights that were most delayed (left latest after scheduled departure time) and least delayed (left ahead of scheduled time).

3: Sort flights to find the fastest flights. Interpret fastest to mean shortest time in the air.

arrange(flights, air_time)

Optional challenge: fastest flight could refer to fastest air speed. Speed is measured in miles per hour but time is minutes. Arrange the data by fastest air speed.

4: Which flights travelled the longest? Which travelled the shortest?

arrange(flights, desc(distance))
arrange(flights, distance)

5.4 Select columns with select()

select(flights, year, month, day)
select(flights, year:day)
select(flights, -(year:day))
rename(flights, tail_num = tailnum)
select(flights, time_hour, air_time, everything())

5.4 Questions

1: Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights. Find at least three ways.

select(flights, dep_time,  dep_delay, arr_time, arr_delay)
flights %>% select(dep_time,  dep_delay, arr_time, arr_delay)
select(flights, c(dep_time,  dep_delay, arr_time, arr_delay))

2: What happens if you include the name of a variable multiple times in a select() call?

select(flights, dep_time, dep_time)

It only selects/lists the variable once, since it is the same variable.

3: What does the one_of() function do? Why might it be helpful in conjunction with this vector?

vars <- c("year", "month", "day", "dep_delay", "arr_delay")
flights %>% select(one_of(vars))

This is helpful to know which variables you have previously used. The function brings all the variables that you have used to your attention (as shown above).

4: Does the result of running the following code surprise you? How do the select helpers deal with case by default? How can you change that default?

`select(flights, contains("TIME"))`
Error: object 'select(flights, contains("TIME"))' not found

No, there are too many variables with the word “time” in it. Therefore, it does not try to overload itself. The “helpers” select everything that has the word “time” in it. By default, it is not case sensitive. You can change this default by using “ignore.case = FALSE”.

LS0tDQp0aXRsZTogIkhXMDUgUGFydCAxOiBDb21wbGV0ZSB0aGUgc2VjdGlvbnMiDQphdXRob3I6ICJDaHJpc3RpbmEgQmVhdWZvcmQiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiAlWScpYCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KLSBDaGFuZ2UgInlvdXIgbmFtZSIgaW4gdGhlIFlBTUwgaGVhZGVyIGFib3ZlIHRvIHlvdXIgbmFtZS4NCg0KLSBBcyB1c3VhbCwgZW50ZXIgdGhlIGV4YW1wbGVzIGluIGNvZGUgY2h1bmtzIGFuZCBydW4gdGhlbSwgdW5sZXNzIHRvbGQgb3RoZXJ3aXNlLg0KDQojIyBDaGFwdGVyIDEwOiBUaWJibGVzDQoNClJlYWQgW1I0ZHMgQ2hhcHRlciAxMDogVGliYmxlc10oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei90aWJibGVzLmh0bWwpLCBzZWN0aW9ucyAxLTMuDQoNCiMjIyAxMC4xOiBJbnRyb2R1Y3Rpb24NCg0KTG9hZCB0aGUgdGlkeXZlcnNlIHBhY2thZ2UuDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCg0KIyMjIDEwLjI6IENyZWF0aW5nIHRpYmJsZXMNCg0KRW50ZXIgeW91ciBjb2RlIGNodW5rcyBmb3IgU2VjdGlvbiAxMC4yIGhlcmUuDQoNCkRlc2NyaWJlIHdoYXQgZWFjaCBjaHVuayBjb2RlIGRvZXMuIA0KDQpgYGB7cn0NCmFzX3RpYmJsZShpcmlzKQ0KYGBgDQp0aWJibGUgaXMgYSBsaWtlIGFuIGltcHJvdmVkIGZvcm0gb2YgYSBkYXRhLmZyYW1lLg0KDQpgYGB7cn0NCnRpYmJsZSgNCiAgeCA9IDE6NSwgDQogIHkgPSAxLCANCiAgeiA9IHggXiAyICsgeSkNCmBgYA0KdGliYmxlIGRvZXMgbm90IGNoYW5nZSB0aGUgaW5wdXRzIG9yIG5hbWVzIG9mIHZhcmlhYmxlcyBhbmQgbmV2ZXIgY3JlYXRlcyByb3cgbmFtZXMuIA0KDQpgYGB7cn0NCnRiIDwtIHRpYmJsZSgNCiAgYDopYCA9ICJzbWlsZSIsIA0KICBgIGAgPSAic3BhY2UiLA0KICBgMjAwMGAgPSAibnVtYmVyIg0KKQ0KdGINCmBgYA0KYmFjayB0aWNrcyBhbGxvdyB5b3UgdG8gcmVmZXIgdG8gdGhlIHZhcmlhYmxlcyBpbiBub24tc3ludGFjdGljIG5hbWVzLg0KDQpgYGB7cn0NCnRyaWJibGUoDQogIH54LCB+eSwgfnosDQogICMtLXwtLXwtLS0tDQogICJhIiwgMiwgMy42LA0KICAiYiIsIDEsIDguNQ0KKQ0KYGBgDQp0cmliYmxlIG1lYW5zIHRyYW5zcG9zZWQgdGliYmxlLiBJdCBpcyAiY3VzdG9taXplZCBmb3IgZGF0YSBlbnRyeSBpbiBjb2RlOiBjb2x1bW4gaGVhZGluZ3MgYXJlIGRlZmluZWQgYnkgZm9ybXVsYXMgKHN0YXJ0IHdpdGggfikgYW5kIHNlcGFyYXRlZCBieSBjb21tYXMsIHRoaXMgbWFrZXMgaXQgZWFzeSB0byByZWFkLiINCg0KIyMjIDEwLjM6IFRpYmJsZXMgdnMgZGF0YS5mcmFtZQ0KDQpFbnRlciB5b3VyIGNvZGUgY2h1bmtzIGZvciBTZWN0aW9uIDEwLjMgaGVyZS4NCg0KRGVzY3JpYmUgd2hhdCBlYWNoIGNodW5rIGNvZGUgZG9lcy4gDQoNCmBgYHtyfQ0KdGliYmxlKA0KICBhID0gbHVicmlkYXRlOjpub3coKSArIHJ1bmlmKDFlMykgKiA4NjQwMCwNCiAgYiA9IGx1YnJpZGF0ZTo6dG9kYXkoKSArIHJ1bmlmKDFlMykgKiAzMCwNCiAgYyA9IDE6MWUzLA0KICBkID0gcnVuaWYoMWUzKSwNCiAgZSA9IHNhbXBsZShsZXR0ZXJzLCAxZTMsIHJlcGxhY2UgPSBUUlVFKSkNCmBgYA0KVGhpcyBzaG93cyBvbmx5IHRoZSBmaXJzdCB0ZW4gcm93cyBhbmQgY29sdW1ucyB0aGF0IGZpdCBvbiB0aGUgc2NyZWVuLiBUaGlzIGFsbG93cyBsYXJnZSBkYXRhIHRvIGJlIGVhc3kgdG8gd29yayB3aXRoLiANCmBgYHtyfQ0KbnljZmxpZ2h0czEzOjpmbGlnaHRzICU+JSANCiAgcHJpbnQobiA9IDEwLCB3aWR0aCA9IEluZikNCmBgYA0KVGhpcyBhbGxvd3MgeW91IHRvIHByaW50IHRoZSBkYXRhIGZyYW1lIGV4cGxpY2l0bHkgYW5kIGNvbnRyb2wgdGhlIG51bWJlciBvZiByb3dzIGFuZCB0aGUgd2lkdGggb2YgdGhlIGRpc3BsYXkuIHdpZHRoID0gaW5mIHNob3dzIGFsbCB0aGUgY29sdW1ucy4NCg0KYGBge3J9DQpueWNmbGlnaHRzMTM6OmZsaWdodHMgJT4lIA0KICBWaWV3KCkNCmBgYA0KdGhlIHZpZXcoKSBmdW5jdGlvbiBhbGxvd3MgeW91IHRvIHZpZXcgdGhlIHdob2xlIGRhdGEgc2V0IGluIGEgdGFibGUuDQoNCmBgYHtyfQ0KZGYgPC0gdGliYmxlKA0KICB4ID0gcnVuaWYoNSksDQogIHkgPSBybm9ybSg1KSkNCg0KYGBgDQoNCg0KYGBge3J9DQpkZiR4DQpkZltbIngiXV0NCmRmW1sxXV0NCmBgYA0KVGhlc2UgZnVuY3Rpb25zIGFsbG93IHlvdSB0byBleHRyYWN0IGEgc2luZ2xlIHZhcmlhYmxlIGJ5IG5hbWUgb3IgcG9zaXRpb24uDQoNCg0KYGBge3J9DQpkZiAlPiUgLiR4DQoNCmRmICU+JSAuW1sieCJdXQ0KYGBgDQpUaGlzIGFsc28gYWxsb3dzIGV4dHJhY3Rpb24gb2YgYSBzaW5nbGUgdmFyaWFibGUsIGJ1dCB1c2luZyBwaXBlIGFuZCB0aGUgcGxhY2Vob2xkZXIgIi4iIGlzIHVzZWQuDQoNCg0KIyMjIDEwLjQ6IE5vdCByZXF1aXJlZA0KDQojIyMjIFNlY3Rpb24gMTAuNSBRdWVzdGlvbnMNCg0KQW5zd2VyIHRoZSBxdWVzdGlvbnMgKmNvbXBsZXRlbHkuKiBVc2UgY29kZSBjaHVua3MsIHRleHQsIG9yIGJvdGgsIGFzIG5lY2Vzc2FyeS4NCg0KYGBge3J9DQptdGNhcnMNCmBgYA0KDQpgYGB7cn0NCmFzX3RpYmJsZShtdGNhcnMpDQpgYGANCg0KYGBge3J9DQpzdHIobXRjYXJzKQ0KDQpjbGFzcyhtdGNhcnMpDQpgYGANCg0KDQoqKjE6KiogSG93IGNhbiB5b3UgdGVsbCBpZiBhbiBvYmplY3QgaXMgYSB0aWJibGU/IChIaW50OiB0cnkgcHJpbnRpbmcgYG10Y2Fyc2AsIHdoaWNoIGlzIGEgcmVndWxhciBkYXRhIGZyYW1lKS4gSWRlbnRpZnkgYXQgbGVhc3QgdHdvIHdheXMgdG8gdGVsbCBpZiBhbiBvYmplY3QgaXMgYSB0aWJibGUuICpIaW50OiogV2hhdCBkb2VzIGBhc190aWJibGUoKWAgZG8/IFdoYXQgZG9lcyBgY2xhc3MoKWAgZG8/IFdoYXQgZG9lcyBgc3RyKClgIGRvPw0KQSB0aWJibGUgdXNlcyByb3cgbnVtYmVycyBpbnN0ZWFkIG9mIG5hbWVzIGFuZCBkaXNwbGF5cyA5IGNvbHVtbnMgKHdoZXJlYXMgdGhlIGRhdGEgZnJhbWUgb25seSBzaG93cyBzaXggY29sdW1ucy0td2l0aG91dCBzY3JvbGxpbmcpLiBzdHIoKSBsaXN0cyB0aGUgZGF0YSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgZnJhbWUuIENsYXNzKCkgdGVsbHMgeW91IHdoYXQgdHlwZSBvZiBjbGFzcyB0aGUgdmFyaWFibGUgaXM7IGZvciBleGFtcGxlIG10Y2FycyBpcyBhIGRhdGEuZnJhbWUuDQoNCg0KKioyOioqIENvbXBhcmUgYW5kIGNvbnRyYXN0IHRoZSBmb2xsb3dpbmcgb3BlcmF0aW9ucyBvbiBhIGRhdGEuZnJhbWUgYW5kIGVxdWl2YWxlbnQgdGliYmxlLiBXaGF0IGlzIGRpZmZlcmVudD8gV2h5IG1pZ2h0IHRoZSBkZWZhdWx0IGRhdGEgZnJhbWUgYmVoYXZpb3VycyBjYXVzZSB5b3UgZnJ1c3RyYXRpb24/DQoNCmBgYHtyfQ0KZGYgPC0gZGF0YS5mcmFtZShhYmMgPSAxLCB4eXogPSAiYSIpDQpkZiR4DQpkZlssICJ4eXoiXQ0KZGZbLCBjKCJhYmMiLCAieHl6IildDQpgYGANClRoZSBkZWZhdWx0IGRhdGEgZnJhbWUgZnVuY3Rpb25zIGF1dG9tYXRpY2FsbHkgY2hvb3NlIGEgdGl0bGUgZm9yIHlvdXIgcm93cy9jb2x1bW5zLiBJbiB0aWJibGUsIGl0IGRvZXMgbm90IG1ha2UgdXAgbmFtZXMsIGl0IGNob29zZXMgaXQgZnJvbSB0aGUgZGF0YSBnaXZlbi4NCg0KIyMgQ2hhcHRlciAxMTogSW1wb3J0aW5nIGRhdGENCg0KUmVhZCBbUjRkcyBDaGFwdGVyIDExOiBEYXRhIEltcG9ydF0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLWltcG9ydC5odG1sKSwgc2VjdGlvbnMgMSwgMiwgYW5kIDUuDQoNCiMjIyAxMS4xIEludHJvZHVjdGlvbg0KDQpOb3RoaW5nIHRvIGRvIGhlcmUgdW5sZXNzIHlvdSB0b29rIGEgYnJlYWsgYW5kIG5lZWQgdG8gcmVsb2FkIGB0aWR5dmVyc2VgLg0KDQojIyMgMTEuMiBHZXR0aW5nIHN0YXJ0ZWQuDQoNCkRvICpub3QqIHJ1biB0aGUgZmlyc3QgY29kZSBjaHVuayBvZiB0aGlzIHNlY3Rpb24sIHdoaWNoIGJlZ2lucyB3aXRoIGBoZWlnaHRzIDwtIHJlYWRfY3N2KCJkYXRhL2hlaWdodHMuY3N2IilgLiBZb3UgZG8gbm90IGhhdmUgdGhhdCBkYXRhIGZpbGUgc28gdGhlIGNvZGUgd2lsbCBub3QgcnVuLg0KDQpFbnRlciBhbmQgcnVuIHRoZSByZW1haW5pbmcgY2h1bmtzIGluIHRoaXMgc2VjdGlvbi4NCg0KYGBge3J9DQpyZWFkX2NzdigiYSxiLGMNCjEsMiwzDQo0LDUsNiIpDQpgYGANCg0KYGBge3J9DQpyZWFkX2NzdigiVGhlIGZpcnN0IGxpbmUgb2YgbWV0YWRhdGENCiAgVGhlIHNlY29uZCBsaW5lIG9mIG1ldGFkYXRhDQogIHgseSx6DQogIDEsMiwzIiwgc2tpcCA9IDIpDQpgYGANCg0KYGBge3J9DQpyZWFkX2NzdigiIyBBIGNvbW1lbnQgSSB3YW50IHRvIHNraXANCiAgeCx5LHoNCiAgMSwyLDMiLCBjb21tZW50ID0gIiMiKQ0KYGBgDQoNCmBgYHtyfQ0KcmVhZF9jc3YoIjEsMiwzXG40LDUsNiIsIGNvbF9uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KcmVhZF9jc3YoIjEsMiwzXG40LDUsNiIsIGNvbF9uYW1lcyA9IGMoIngiLCAieSIsICJ6IikpDQpgYGANCg0KYGBge3J9DQpyZWFkX2NzdigiYSxiLGNcbjEsMiwuIiwgbmEgPSAiLiIpDQpgYGANCg0KDQojIyMjIDExLjIgUXVlc3Rpb25zDQoNCioqMToqKiBXaGF0IGZ1bmN0aW9uIHdvdWxkIHlvdSB1c2UgdG8gcmVhZCBhIGZpbGUgd2hlcmUgZmllbGRzIHdlcmUgc2VwYXJhdGVkIHdpdGggInwiPw0KYHJlYWRfZGVsaW0oImZpbGUuY3N2IiwgZGVsaW0gPSAifCIpYCBpcyB0aGUgZnVuY3Rpb24geW91IHdvdWxkIHVzZSB0byByZWFkIHRoZSBmaWxlIHdpdGggZW50cmllcyBzZXBhcmF0ZWQgd2l0aCAifCIuDQoNCg0KKioyOioqIChUaGlzIHF1ZXN0aW9uIGlzIG1vZGlmaWVkIGZyb20gdGhlIHRleHQuKSBGaW5pc2ggdGhlIHR3byBsaW5lcyBvZiBgcmVhZF9kZWxpbWAgY29kZSBzbyB0aGF0IHRoZSBmaXJzdCBvbmUgd291bGQgcmVhZCBhIGNvbW1hLXNlcGFyYXRlZCBmaWxlIGFuZCB0aGUgc2Vjb25kIHdvdWxkIHJlYWQgYSB0YWItc2VwYXJhdGVkIGZpbGUuIFlvdSBvbmx5IG5lZWQgdG8gd29ycnkgYWJvdXQgdGhlIGRlbGltaXRlci4gRG8gbm90IHdvcnJ5IGFib3V0IG90aGVyIGFyZ3VtZW50cy4gUmVwbGFjZSB0aGUgZG90cyBpbiBlYWNoIGxpbmUgd2l0aCB0aGUgcmVzdCBvZiB5b3VyIGNvZGUuIA0KDQojIENvbW1hLXNlcGFyYXRlZA0KYGZpbGUgPC0gcmVhZF9kZWxpbSgiZmlsZS5jc3YiLCBkZWxpbSA9ICIsIilgDQoNCiMgVGFiLXNlcGFyYXRlZA0KYGZpbGUgPC0gcmVhZF9kZWxpbSgiZmlsZS5jc3YiLCBkZWxpbSA9ICJcdCIpYA0KDQoNCioqMzoqKiBXaGF0IGFyZSB0aGUgdHdvIG1vc3QgaW1wb3J0YW50IGFyZ3VtZW50cyB0byBgcmVhZF9md2YoKWA/IFdoeT8NCmNvbF9wb3NpdGlvbiBhbmQgY29sX3R5cGVzIGFyZSB0aGUgbW9zdCBpbXBvcnRhbnQgYXJndW1lbnRzIHRvIHJlYWRfZndmIGJlY2F1c2UgdGhleSBhbGxvdyB5b3UgdG8gbmFtZSB5b3VyIGNvbHVtbnMgYW5kIGRldGVybWluZSB0aGUgdHlwZSBvZiBkYXRhIGxpc3RlZCBpbiB0aGUgY29sdW1ucy4NCg0KKio0OioqIFNraXAgdGhpcyBxdWVzdGlvbg0KDQoNCioqNTogKiogSWRlbnRpZnkgd2hhdCBpcyB3cm9uZyB3aXRoIGVhY2ggb2YgdGhlIGZvbGxvd2luZyBpbmxpbmUgQ1NWIGZpbGVzLiBXaGF0IGhhcHBlbnMgd2hlbiB5b3UgcnVuIHRoZSBjb2RlPw0KDQpgYGB7cn0NCnJlYWRfY3N2KCJhLGJcbjEsMiwzXG40LDUsNiIpDQpyZWFkX2NzdigiYSxiLGNcbjEsMlxuMSwyLDMsNCIpDQpyZWFkX2NzdigiYSxiXG5cIjEiKQ0KcmVhZF9jc3YoImEsYlxuMSwyXG5hLGIiKQ0KcmVhZF9jc3YoImE7YlxuMTszIikNCmBgYA0KInBhcnNpbmcgZmFpbHVyZXMiIGlzIHRoZSBlcnJvciBtZXNzYWdlIGFzc29jaWF0ZWQgd2l0aCB0aGUgZmlyc3QgZmlsZS4gVGhpcyBpcyBiZWNhdXNlIGl0IGlzIHNldCBmb3IgMiBjb2x1bW5zIGFuZCBzb21lIG9mIHRoZSBkYXRhIGhhcyB0aHJlZSBjb2x1bW5zLiBUaGlzIGNhdXNlcyBzb21lIG9mIHRoZSBpbmZvcm1hdGlvbiB0byBiZSBsZWZ0IG91dCBvZiB0aGUgdGFibGUgYW5kIG5vdCBkaXNwbGF5ZWQuIFRoZSBuZXh0IGZpbGUgaXMgc2V0IGZvciB0aHJlZSBjb2x1bW5zLCBidXQgb25seSBoYXMgMiBlbnRyaWVzLiBUaGUgbmV4dCBmaWxlIGlzIHNldCBmb3IgMiBjb2x1bW5zLCBidXQgb25seSBoYXMgb25lIGVudHJ5LiBUaGUgbmV4dCBmaWxlIGhhcyBzb21lIG9mIHRoZSBkYXRhIGxpc3RlZCBhcyBoZWFkZXJzIGFuZCB0aGlzIGlzIHJlZHVuZGFudC4gVGhpcyBpcyBkdWUgdG8gZGF0YSBiZWluZyBpbXByb3Blcmx5IHJlY29yZGVkLiBUaGUgbmV4dCBmaWxlIGlzIGxpc3RlZCB3aXRoIHNlbWljb2xvbnMsIGJ1dCB0aGUgZnVuY3Rpb24gdXNlZCByZWFkcyBlbnRyaWVzIHNlcGFyYXRlZCB3aXRoIGNvbW1hcy4gVGhpcyBjYXVzZXMgdGhlIGRhdGEgdG8gYmUgbGlzdGVkIGluIHRoZSBzYW1lIGNvbHVtbiBiZWNhdXNlIHRpYmJsZSBkb2VzIG5vdCByZWNvZ25pemUgdGhlIGVudHJpZXMgYXMgc2VwYXJhdGUgZW50cmllcy4NCg0KDQojIyMgMTEuMyBhbmQgMTEuNDogTm90IHJlcXVpcmVkDQoNCiMjIyAxMS41OiBXcml0aW5nIHRvIGEgZmlsZQ0KDQpKdXN0IHJlYWQgdGhpcyBzZWN0aW9uLiBZb3UgbWF5IGZpbmQgaXQgaGVscGZ1bCBpbiB0aGUgZnV0dXJlIHRvIHNhdmUgYSBkYXRhIGZpbGUgdG8geW91ciBoYXJkIGRyaXZlLiBJdCBpcyBiYXNpY2FsbHkgdGhlIHNhbWUgZm9ybWF0IGFzIHJlYWRpbmcgYSBmaWxlLCBleGNlcHQgdGhhdCB5b3UgbXVzdCBzcGVjaWZ5IHRoZSBkYXRhIG9iamVjdCB0byBzYXZlLCBpbiBhZGRpdGlvbiB0byB0aGUgcGF0aCBhbmQgZmlsZSBuYW1lLg0KDQojIyMgMTEuNiBOb3QgcmVxdWlyZWQNCg0KIyMgQ2hhcHRlciAxODogUGlwZXMNCg0KUmVhZCBbUjRkcyBDaGFwdGVyIDE4OiBQaXBlc10oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9waXBlcy5odG1sKSwgc2VjdGlvbnMgMS0zLg0KDQpOb3RoaW5nIHRvIGRvIG90aGVyd2lzZSBmb3IgdGhpcyBjaGFwdGVyLiBJcyB0aGlzIGVhc3kgb3Igd2hhdD8NCg0KKipOb3RlOioqIFRyeWluZyB1c2luZyBwaXBlcyBmb3IgYWxsIG9mIHRoZSByZW1haW5pbmcgZXhhbXBsZXMuIFRoYXQgd2lsbCBoZWxwIHlvdSB1bmRlcnN0YW5kIHRoZW0uDQoNCiMjIENoYXB0ZXIgMTI6IFRpZHkgRGF0YQ0KDQpSZWFkIFtSNGRzIENoYXB0ZXIgMTI6IFRpZHkgRGF0YV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei90aWR5LWRhdGEuaHRtbCksIHNlY3Rpb25zIDEtMywgNy4gDQoNCiMjIyAxMi4xIEludHJvZHVjdGlvbg0KDQpOb3RoaW5nIHRvIGRvIGhlcmUgdW5sZXNzIHlvdSB0b29rIGEgYnJlYWsgYW5kIG5lZWQgdG8gcmVsb2FkIHRoZSBgdGlkeXZlcnNlLmANCg0KIyMjIDEyLjIgVGlkeSBkYXRhDQoNClN0dWR5IEZpZ3VyZSAxMi4xIGFuZCByZWxhdGUgdGhlIGRpYWdyYW0gdG8gdGhlIHRocmVlIHJ1bGVzIGxpc3RlZCBqdXN0IGFib3ZlIHRoZW0uIFJlbGF0ZSB0aGF0IGJhY2sgdG8gdGhlIGV4YW1wbGUgSSBnYXZlIHlvdSBpbiB0aGUgbm90ZXMuIEJlYXIgdGhpcyBpbiBtaW5kIGFzIHlvdSBtYWtlIGRhdGEgdGlkeSBpbiB0aGUgc2Vjb25kIHBhcnQgb2YgdGhpcyBhc3NpZ25tZW50Lg0KDQpZb3UgZG8gbm90IGhhdmUgdG8gcnVuIGFueSBvZiB0aGUgZXhhbXBsZXMgaW4gdGhpcyBzZWN0aW9uLg0KDQojIyMgMTIuMw0KDQpSZWFkIGFuZCBydW4gdGhlIGV4YW1wbGVzIHRocm91Z2ggc2VjdGlvbiAxMi4zLjEgKGdhdGhlcmluZyksIGluY2x1ZGluZyB0aGUgZXhhbXBsZSB3aXRoIGBsZWZ0X2pvaW4oKWAuIFdlJ2xsIGNvdmVyIGpvaW5zIGxhdGVyLg0KDQpgYGB7cn0NCnRhYmxlNGENCmBgYA0KDQpgYGB7cn0NCnRhYmxlNGEgJT4lIA0KICBnYXRoZXIoYDE5OTlgLCBgMjAwMGAsIGtleSA9ICJ5ZWFyIiwgdmFsdWUgPSAiY2FzZXMiKQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGU0YiAlPiUgDQogIGdhdGhlcihgMTk5OWAsIGAyMDAwYCwga2V5ID0gInllYXIiLCB2YWx1ZSA9ICJwb3B1bGF0aW9uIikNCmBgYA0KDQpgYGB7cn0NCnRpZHk0YSA8LSB0YWJsZTRhICU+JSANCiAgZ2F0aGVyKGAxOTk5YCwgYDIwMDBgLCBrZXkgPSAieWVhciIsIHZhbHVlID0gImNhc2VzIikNCnRpZHk0YiA8LSB0YWJsZTRiICU+JSANCiAgZ2F0aGVyKGAxOTk5YCwgYDIwMDBgLCBrZXkgPSAieWVhciIsIHZhbHVlID0gInBvcHVsYXRpb24iKQ0KbGVmdF9qb2luKHRpZHk0YSwgdGlkeTRiKQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUyDQpgYGANCg0KYGBge3J9DQp0YWJsZTIgJT4lDQogICAgc3ByZWFkKGtleSA9IHR5cGUsIHZhbHVlID0gY291bnQpDQpgYGANCg0KDQojIyMjIDEyLjMgUXVlc3Rpb25zDQoNCioqMjoqKiBXaHkgZG9lcyB0aGlzIGNvZGUgZmFpbD8gRml4IGl0IHNvIGl0IHdvcmtzLg0KDQpgYGB7cn0NCnRhYmxlNGEgJT4lIA0KICBnYXRoZXIoMTk5OSwgMjAwMCwga2V5ID0gInllYXIiLCB2YWx1ZSA9ICJjYXNlcyIpDQojPiBFcnJvciBpbiBpbmRzX2NvbWJpbmUoLnZhcnMsIGluZF9saXN0KTogUG9zaXRpb24gbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIG4NCmBgYA0KDQpgYGB7cn0NCnRhYmxlNGEgJT4lIA0KICBnYXRoZXIoYDE5OTlgLCBgMjAwMGAsIGtleSA9ICJ5ZWFyIiwgdmFsdWUgPSAiY2FzZXMiKQ0KYGBgDQoNClR0aGVyZSBtdXN0IGJlIGJhY2t0aWNrcyBzdXJyb3VuZGluZyB0aGUgeWVhcnMuDQoNClRoYXQgaXMgYWxsIGZvciBDaGFwdGVyIDEyLiBPbiB0byB0aGUgbGFzdCBjaGFwdGVyLg0KDQoNCiMjIENoYXB0ZXIgNTogRGF0YSB0cmFuc2Zvcm1hdGlvbg0KDQpSZWFkIFtSNGRzIENoYXB0ZXIgNTogRGF0YSBUcmFuc2Zvcm1hdGlvbl0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei90cmFuc2Zvcm0uaHRtbCksIHNlY3Rpb25zIDEtNC4NCg0KVGltZSB0byBbZ2V0IHNtYWxsLl0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1HT3JkekNIbnB3NCkgDQoNCiMjIyA1LjE6IEludHJvZHVjdGlvbg0KDQpMb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzLiBBcyB1c3VhbCwgdHlwZSB0aGUgZXhhbXBsZXMgaW50byBhbmQgcnVuIHRoZSBjb2RlIGNodW5rcy4NCg0KYGBge3J9DQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCmBgYHtyfQ0KbnljZmxpZ2h0czEzOjpmbGlnaHRzDQpgYGANCg0KYGBge3J9DQpmbGlnaHRzDQpgYGANCg0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMSwgZGF5ID09IDEpDQpgYGANCg0KYGBge3J9DQpqYW4xIDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxLCBkYXkgPT0gMSkNCmBgYA0KDQpgYGB7cn0NCihkZWMyNSA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMTIsIGRheSA9PSAyNSkpDQojPiAjIEEgdGliYmxlOiA3MTkgeCAxOQ0KYGBgDQoNCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIG1vbnRoID09IDEpDQpgYGANCg0KYGBge3J9DQpzcXJ0KDIpIF4gMiA9PSAyDQpgYGANCg0KYGBge3J9DQpuZWFyKHNxcnQoMikgXiAyLCAgMikNCg0KbmVhcigxIC8gNDkgKiA0OSwgMSkNCmBgYA0KDQoNCg0KIyMjIDUuMjogRmlsdGVyIHJvd3Mgd2l0aCBgZmlsdGVyKClgDQoNClN0dWR5IEZpZ3VyZSA1LjEgY2FyZWZ1bGx5LiBPbmNlIHlvdSBsZWFybiB0aGUgYCZgLCBgfGAsIGFuZCBgIWAgbG9naWMsIHlvdSB3aWxsIGZpbmQgdGhlbSB0byBiZSB2ZXJ5IHBvd2VyZnVsIHRvb2xzLg0KDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxMSB8IG1vbnRoID09IDEyKQ0KYGBgDQoNCmBgYHtyfQ0Kbm92X2RlYyA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggJWluJSBjKDExLCAxMikpDQpgYGANCg0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgIShhcnJfZGVsYXkgPiAxMjAgfCBkZXBfZGVsYXkgPiAxMjApKQ0KZmlsdGVyKGZsaWdodHMsIGFycl9kZWxheSA8PSAxMjAsIGRlcF9kZWxheSA8PSAxMjApDQpgYGANCg0KYGBge3J9DQpOQSA+IDUNCjEwID09IE5BDQpOQSArIDEwDQpOQSAvIDINCmBgYA0KYGBge3J9DQpOQSA9PSBOQQ0KYGBgDQoNCmBgYHtyfQ0KeCA8LSBOQQ0KDQp5IDwtIE5BDQoNCnggPT0geQ0KYGBgDQoNCmBgYHtyfQ0KaXMubmEoeCkNCmBgYA0KDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gYygxLCBOQSwgMykpDQpmaWx0ZXIoZGYsIHggPiAxKQ0KDQpmaWx0ZXIoZGYsIGlzLm5hKHgpIHwgeCA+IDEpDQpgYGANCg0KDQojIyMjIDUuMiBRdWVzdGlvbnMNCg0KKioxLjE6KiogRmluZCBhbGwgZmxpZ2h0cyB3aXRoIGEgZGVsYXkgb2YgMiBob3VycyBvciBtb3JlLg0KDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCAoYXJyX2RlbGF5ID4gMTIwIHwgZGVwX2RlbGF5ID4gMTIwKSkNCmBgYA0KDQoNCg0KKioxLjI6KiogRmxldyB0byBIb3VzdG9uIChJQUggb3IgSE9VKQ0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgZGVzdCA9PSAnSUFIJyB8IGRlc3QgPT0gJ0hPVScpDQpgYGANCg0KDQoNCioqMS4zOioqIFdlcmUgb3BlcmF0ZWQgYnkgVW5pdGVkIChVQSksIEFtZXJpY2FuIChBQSksIG9yIERlbHRhIChETCkuDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBjYXJyaWVyID09ICdVQScgfCBjYXJyaWVyID09ICdBQScgfCBjYXJyaWVyID09ICdETCcpDQpgYGANCg0KDQoqKjEuNDoqKiBEZXBhcnRlZCBpbiBzdW1tZXIgKEp1bHksIEF1Z3VzdCwgYW5kIFNlcHRlbWJlcikuDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBtb250aCA+PSA3ICYgbW9udGggPD0gOSkNCmBgYA0KDQoNCioqMS41OioqIEFycml2ZWQgbW9yZSB0aGFuIHR3byBob3VycyBsYXRlLCBidXQgZGlkbuKAmXQgbGVhdmUgbGF0ZS4NCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIGFycl9kZWxheSA+IDEyMCwgZGVwX2RlbGF5IDw9IDApDQpgYGANCg0KDQoqKjEuNjoqKiBXZXJlIGRlbGF5ZWQgYnkgYXQgbGVhc3QgYW4gaG91ciwgYnV0IG1hZGUgdXAgb3ZlciAzMCBtaW51dGVzIGluIGZsaWdodC4gVGhpcyBpcyBhIHRyaWNreSBvbmUuIERvIHlvdXIgYmVzdC4NCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIGRlcF9kZWxheSA+PSA2MCwgZGVwX2RlbGF5LWFycl9kZWxheSA+IDMwKQ0KYGBgDQoNCg0KKioxLjc6KiogRGVwYXJ0ZWQgYmV0d2VlbiBtaWRuaWdodCBhbmQgNmFtIChpbmNsdXNpdmUpDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBkZXBfdGltZSA8PTYwMCB8IGRlcF90aW1lID09IDI0MDApDQpgYGANCg0KDQoqKjI6KiogQW5vdGhlciB1c2VmdWwgZHBseXIgZmlsdGVyaW5nIGhlbHBlciBpcyBgYmV0d2VlbigpYC4gV2hhdCBkb2VzIGl0IGRvPyBDYW4geW91IHVzZSBpdCB0byBzaW1wbGlmeSB0aGUgY29kZSBuZWVkZWQgdG8gYW5zd2VyIHRoZSBwcmV2aW91cyBjaGFsbGVuZ2VzPw0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgYmV0d2Vlbihtb250aCwgNywgOSkpDQpmaWx0ZXIoZmxpZ2h0cywgIWJldHdlZW4oZGVwX3RpbWUsIDYwMSwgMjM1OSkpDQpgYGANCkl0IHVzZXMgdGhlIGRhdGEgYmV0d2VlbiB0aGUgdmFyaWFibGVzIGxpc3RlZC4gSXQgZG9lcyBzaW1wbGlmeSB0aGUgbGFzdCB0d28gcXVlc3Rpb25zIQ0KDQoqKjM6KiogSG93IG1hbnkgZmxpZ2h0cyBoYXZlIGEgbWlzc2luZyBkZXBfdGltZT8gV2hhdCBvdGhlciB2YXJpYWJsZXMgYXJlIG1pc3Npbmc/IFdoYXQgbWlnaHQgdGhlc2Ugcm93cyByZXByZXNlbnQ/DQpgYGB7cn0NCnN1bW1hcnkoZmxpZ2h0cykNCmBgYA0KDQo4MjU1IGhhdmUgbWlzc2luZyBkZXBfdGltZSBhbmQgZGVwX2RlbGF5LiA4NzEzIG1pc3NpbmcgYXJyX3RpbWUuIDk0MzAgbWlzc2luZyBhcnJfZGVsYXkuIA0KOTQzMCBtaXNzaW5nIGFpcl90aW1lLiBUaGVzZSByb3dzIG1pZ2h0IHJlcHJlc2VudCBlbXB0eSByb3dzIG9yIGp1c3QgZm9yZ290dGVuIGRhdGEgKGh1bWFuIGVycm9yKS4NCg0KDQoqKjQ6KiogV2h5IGlzIGBOQSBeIDBgIG5vdCBtaXNzaW5nPyBXaHkgaXMgYE5BIHwgVFJVRWAgbm90IG1pc3Npbmc/IFdoeSBpcyBgRkFMU0UgJiBOQWAgbm90IG1pc3Npbmc/IENhbiB5b3UgZmlndXJlIG91dCB0aGUgZ2VuZXJhbCBydWxlPyAoYE5BICogMGAgaXMgYSB0cmlja3kgY291bnRlcmV4YW1wbGUhKQ0KYGBge3J9DQpOQSBeIDANCk5BIHwgVFJVRQ0KRkFMU0UgJiBOQQ0KYGBgDQpOQSBeIDAgPSAxLiBOQSB8IFRSVUUgbWVhbnMgaWYgZWl0aGVyIE5BIG9yIHRydWUgaXMgdHJ1ZSwgdGhlbiB0aGUgd2hvbGUgc2V0ID0gVFJVRS4gRkFMU0UgJiBOQSBpcyBub3QgbWlzc2luZzsgb25lIG9mIHRoZSB0ZXJtcyA9IEZBTFNFLiBJZiBvbmUgdGVybSBpcyBjb3JyZWN0LCB0aGVuIHRoZSBmdW5jdGlvbiBjb3VudHMgdGhlIHdob2xlIHRlcm0gYXMgY29ycmVjdCBzZWVtcyB0byBiZSB0aGUgZ2VuZXJhbCBydWxlLg0KDQoqKk5vdGU6KiogRm9yIHNvbWUgY29udGV4dCwgc2VlIFt0aGlzIHRocmVhZF0oaHR0cHM6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMTYvMDcvdW5kZXJzdGFuZGluZy1uYS1pbi1yLmh0bWwpDQoNCg0KIyMjIDUuMyBBcnJhbmdlIHdpdGggYGFycmFuZ2UoKWANCg0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpDQpgYGANCg0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIGRlc2MoZGVwX2RlbGF5KSkNCmBgYA0KDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gYyg1LCAyLCBOQSkpDQphcnJhbmdlKGRmLCB4KQ0KYGBgDQoNCmBgYHtyfQ0KYXJyYW5nZShkZiwgZGVzYyh4KSkNCmBgYA0KDQoNCiMjIyMgNS4zIFF1ZXN0aW9ucw0KDQoqKjE6KiogSG93IGNvdWxkIHlvdSB1c2UgYGFycmFuZ2UoKWAgdG8gc29ydCBhbGwgbWlzc2luZyB2YWx1ZXMgdG8gdGhlIHN0YXJ0PyAoSGludDogdXNlIGlzLm5hKCkpLiAqKk5vdGU6KiogVGhpcyBvbmUgc2hvdWxkIHN0aWxsIGhhdmUgdGhlIGVhcmxpZXN0IGRlcGFydHVyZSBkYXRlcyBhZnRlciB0aGUgYE5BYHMuICpIaW50OiogV2hhdCBkb2VzIGBkZXNjKClgIGRvPw0KYGBge3J9DQphcnJhbmdlKGRmLCBkZXNjKGlzLm5hKHgpKSkNCmBgYA0KDQoNCg0KKioyOioqIFNvcnQgZmxpZ2h0cyB0byBmaW5kIHRoZSBtb3N0IGRlbGF5ZWQgZmxpZ2h0cy4gRmluZCB0aGUgZmxpZ2h0cyB0aGF0IGxlZnQgZWFybGllc3QuIA0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIGRlc2MoZGVwX2RlbGF5KSkNCmFycmFuZ2UoZmxpZ2h0cywgZGVwX2RlbGF5KQ0KYGBgDQoNCg0KVGhpcyBxdWVzdGlvbiBpcyBhc2tpbmcgZm9yIHRoZSBmbGlnaHRzIHRoYXQgd2VyZSBtb3N0IGRlbGF5ZWQgKGxlZnQgbGF0ZXN0IGFmdGVyIHNjaGVkdWxlZCBkZXBhcnR1cmUgdGltZSkgYW5kIGxlYXN0IGRlbGF5ZWQgKGxlZnQgYWhlYWQgb2Ygc2NoZWR1bGVkIHRpbWUpLg0KDQoNCioqMzoqKiBTb3J0IGZsaWdodHMgdG8gZmluZCB0aGUgZmFzdGVzdCBmbGlnaHRzLiBJbnRlcnByZXQgZmFzdGVzdCB0byBtZWFuIHNob3J0ZXN0IHRpbWUgaW4gdGhlIGFpci4NCmBgYHtyfQ0KYXJyYW5nZShmbGlnaHRzLCBhaXJfdGltZSkNCmBgYA0KDQoNCg0KKk9wdGlvbmFsIGNoYWxsZW5nZToqIGZhc3Rlc3QgZmxpZ2h0IGNvdWxkIHJlZmVyIHRvIGZhc3Rlc3QgYWlyIHNwZWVkLiBTcGVlZCBpcyBtZWFzdXJlZCBpbiBtaWxlcyBwZXIgaG91ciBidXQgdGltZSBpcyBtaW51dGVzLiBBcnJhbmdlIHRoZSBkYXRhIGJ5IGZhc3Rlc3QgYWlyIHNwZWVkLg0KDQoNCioqNDoqKiBXaGljaCBmbGlnaHRzIHRyYXZlbGxlZCB0aGUgbG9uZ2VzdD8gV2hpY2ggdHJhdmVsbGVkIHRoZSBzaG9ydGVzdD8NCmBgYHtyfQ0KYXJyYW5nZShmbGlnaHRzLCBkZXNjKGRpc3RhbmNlKSkNCmFycmFuZ2UoZmxpZ2h0cywgZGlzdGFuY2UpDQpgYGANCg0KDQojIyMgNS40IFNlbGVjdCBjb2x1bW5zIHdpdGggYHNlbGVjdCgpYA0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkNCmBgYA0KDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCB5ZWFyOmRheSkNCmBgYA0KDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCAtKHllYXI6ZGF5KSkNCmBgYA0KDQpgYGB7cn0NCnJlbmFtZShmbGlnaHRzLCB0YWlsX251bSA9IHRhaWxudW0pDQpgYGANCg0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgdGltZV9ob3VyLCBhaXJfdGltZSwgZXZlcnl0aGluZygpKQ0KYGBgDQoNCg0KIyMjIyA1LjQgUXVlc3Rpb25zDQoNCioqMToqKiBCcmFpbnN0b3JtIGFzIG1hbnkgd2F5cyBhcyBwb3NzaWJsZSB0byBzZWxlY3QgYGRlcF90aW1lYCwgYGRlcF9kZWxheWAsIGBhcnJfdGltZWAsIGFuZCBgYXJyX2RlbGF5YCBmcm9tIGZsaWdodHMuIEZpbmQgYXQgbGVhc3QgdGhyZWUgd2F5cy4NCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIGRlcF90aW1lLCAgZGVwX2RlbGF5LCBhcnJfdGltZSwgYXJyX2RlbGF5KQ0KZmxpZ2h0cyAlPiUgc2VsZWN0KGRlcF90aW1lLCAgZGVwX2RlbGF5LCBhcnJfdGltZSwgYXJyX2RlbGF5KQ0Kc2VsZWN0KGZsaWdodHMsIGMoZGVwX3RpbWUsICBkZXBfZGVsYXksIGFycl90aW1lLCBhcnJfZGVsYXkpKQ0KYGBgDQoNCg0KKioyOioqIFdoYXQgaGFwcGVucyBpZiB5b3UgaW5jbHVkZSB0aGUgbmFtZSBvZiBhIHZhcmlhYmxlIG11bHRpcGxlIHRpbWVzIGluIGEgYHNlbGVjdCgpYCBjYWxsPw0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgZGVwX3RpbWUsIGRlcF90aW1lKQ0KYGBgDQoNCkl0IG9ubHkgc2VsZWN0cy9saXN0cyB0aGUgdmFyaWFibGUgb25jZSwgc2luY2UgaXQgaXMgdGhlIHNhbWUgdmFyaWFibGUuDQoNCioqMzoqKiBXaGF0IGRvZXMgdGhlIGBvbmVfb2YoKWAgZnVuY3Rpb24gZG8/IFdoeSBtaWdodCBpdCBiZSBoZWxwZnVsIGluIGNvbmp1bmN0aW9uIHdpdGggdGhpcyB2ZWN0b3I/DQoNCmBgYHtyfQ0KdmFycyA8LSBjKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJkZXBfZGVsYXkiLCAiYXJyX2RlbGF5IikNCmBgYA0KDQoNCmBgYHtyfQ0KZmxpZ2h0cyAlPiUgc2VsZWN0KG9uZV9vZih2YXJzKSkNCmBgYA0KDQpUaGlzIGlzIGhlbHBmdWwgdG8ga25vdyB3aGljaCB2YXJpYWJsZXMgeW91IGhhdmUgcHJldmlvdXNseSB1c2VkLiBUaGUgZnVuY3Rpb24gYnJpbmdzIGFsbCB0aGUgdmFyaWFibGVzIHRoYXQgeW91IGhhdmUgdXNlZCB0byB5b3VyIGF0dGVudGlvbiAoYXMgc2hvd24gYWJvdmUpLg0KDQoqKjQ6KiogRG9lcyB0aGUgcmVzdWx0IG9mIHJ1bm5pbmcgdGhlIGZvbGxvd2luZyBjb2RlIHN1cnByaXNlIHlvdT8gSG93IGRvIHRoZSBzZWxlY3QgaGVscGVycyBkZWFsIHdpdGggY2FzZSBieSBkZWZhdWx0PyBIb3cgY2FuIHlvdSBjaGFuZ2UgdGhhdCBkZWZhdWx0Pw0KDQpgYGB7cn0NCmBzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoIlRJTUUiKSlgDQpgYGANCg0KTm8sIHRoZXJlIGFyZSB0b28gbWFueSB2YXJpYWJsZXMgd2l0aCB0aGUgd29yZCAidGltZSIgaW4gaXQuIFRoZXJlZm9yZSwgaXQgZG9lcyBub3QgdHJ5IHRvIG92ZXJsb2FkIGl0c2VsZi4gVGhlICJoZWxwZXJzIiBzZWxlY3QgZXZlcnl0aGluZyB0aGF0IGhhcyB0aGUgd29yZCAidGltZSIgaW4gaXQuIEJ5IGRlZmF1bHQsIGl0IGlzIG5vdCBjYXNlIHNlbnNpdGl2ZS4gWW91IGNhbiBjaGFuZ2UgdGhpcyBkZWZhdWx0IGJ5IHVzaW5nICJpZ25vcmUuY2FzZSA9IEZBTFNFIi4NCg0KDQoNCg==